﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Drawing = System.Drawing;
using MenuItem = System.Windows.Forms.MenuItem;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using AVIFile;
using Common;
using Common.Control;
using Common.Control.Window;
using Common.DataModels;
using DesktopDuplication;
using Point = Common.DataModels.Point;
using FFmpeg.AutoGen;
using VideoWriter;
using System.Runtime.InteropServices;

namespace ScreenStudio
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private const int FPS = 30;
        private Mp4VideoWriter videoWriter;
        private AudioSource audioSource;

        #region 属性

        private DateTime videoStartTime;

        private RecordingData recordingData;
        private List<Point> points;
        #endregion

        /// <summary>
        /// 托盘图标
        /// </summary>
        private System.Windows.Forms.NotifyIcon notifyIcon = null;

        private MenuItem item;

        /// <summary>
        /// 视频录制线程运行标记
        /// </summary>
        private bool recordingIsRun = false;

        /// <summary>
        /// 之前视频是否正在录制
        /// </summary>
        private bool lastRecordingIsRun = false;

        public MainWindow()
        {
            InitializeComponent();
            InitialTray();
            FFmpegBinariesHelper.RegisterFFmpegBinaries();
        }

        private void closeButton_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }


        private void Window_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                this.DragMove();
            }
        }

        private void openButton_Click(object sender, RoutedEventArgs e)
        {
            string file = OpenVideoFile();
            if (string.IsNullOrWhiteSpace(file)) return;
            VideoPlayWindow videoPlayWindow = new VideoPlayWindow(file);
            videoPlayWindow.Show();
        }


        private void recodingButton_Click(object sender, RoutedEventArgs e)
        {
            if (!recordingIsRun)
            {
                StartRecording();
            }
            else
            {
                StopRecording();
            }
        }

        private async void RunDesktopCapture()
        {
            await Task.Run(() =>
            {
                while (recordingIsRun)
                {
                    Thread.Sleep(1000 / FPS);
                    DesktopFrame frame = null;
                    try
                    {
                        frame = DesktopDuplicator.Instance.GetLatestFrame();
                    }
                    catch (Exception e)
                    {
                        throw e;
                    }
                    finally
                    {
                        if (frame?.DesktopImage != null)
                        {
                            byte[] buffer = new byte[frame.DesktopImage.Width * frame.DesktopImage.Height * 3];
                            var data = frame.DesktopImage.LockBits(new Drawing.Rectangle(0, 0, frame.DesktopImage.Width, frame.DesktopImage.Height), Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                            Marshal.Copy(data.Scan0, buffer, 0, buffer.Length);
                            frame.DesktopImage.UnlockBits(data);
                            videoWriter.WriteFrame(buffer);
                        }
                    }
                }
                Console.WriteLine("RunDesktopCapture() -> End");
                audioSource.OnGetPcmData -= this.OnGetPcmData;
                audioSource.Dispose();
                videoWriter.Dispose();
            });
        }

        private void InitialTray()
        {
            //设置托盘的各个属性
            notifyIcon = new System.Windows.Forms.NotifyIcon();
            notifyIcon.BalloonTipText = "Program Startup";
            notifyIcon.Text = "icon";
            notifyIcon.Icon = new System.Drawing.Icon(System.Windows.Forms.Application.StartupPath + "\\image\\screen.ico");
            notifyIcon.Visible = true;
            notifyIcon.ShowBalloonTip(2000);
            notifyIcon.MouseClick += new System.Windows.Forms.MouseEventHandler(notifyIcon_MouseClick);

            //设置菜单项
            MenuItem show = new System.Windows.Forms.MenuItem("Show Main Window");
            show.Click += show_click;
            //设置菜单项
            MenuItem start = new System.Windows.Forms.MenuItem("Start Recording");
            start.Click += start_click;
            //退出菜单项
            MenuItem exit = new System.Windows.Forms.MenuItem("Exit");
            exit.Click += exit_Click;

            //关联托盘控件
            MenuItem[] childen = new MenuItem[] { show, start, exit };
            notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(childen);
            item = start;
        }



        /// <summary>
        /// 停止录制按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void start_click(object sender, EventArgs e)
        {
            if (!recordingIsRun)
            {
                StartRecording();
            }
            else
            {
                StopRecording();
            }
        }

        /// <summary>
        /// 开始捕获鼠标位置
        /// </summary>
        private void RunMouseCapture()
        {
            MousePosition.Instance.OnGetMousePosition += this.OnGetMousePosition;
            MousePosition.Instance.Start();
        }

        /// <summary>
        /// 获得鼠标位置回调
        /// </summary>
        /// <param name="p"></param>
        private void OnGetMousePosition(POINT p)
        {
            Console.WriteLine($"{p.X},{p.Y}");
            Point point = new Point
            {
                TimeStamp = DateTime.Now.Ticks,
                X = p.X,
                Y = p.Y
            };

            if (recordingData != null)
            {
                if (recordingIsRun)
                {
                    if (points == null)
                        points = new List<Point>();
                    points.Add(point);
                }

                if (recordingIsRun != lastRecordingIsRun)
                {
                    lastRecordingIsRun = recordingIsRun;

                    if (!recordingIsRun)
                    {
                        points = points.GroupBy(x => x.TimeStamp).Select(x => x.First()).OrderBy(x => x.TimeStamp).ToList();
                        recordingData.StartTime = points.First().TimeStamp;
                        recordingData.EndTime = points.Last().TimeStamp;
                        try
                        {
                            DBManager.Instance.SaveRecording(recordingData);
                            DBManager.Instance.SavePoints(points);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                        points.Clear();
                        recordingData = null;
                    }
                }
            }
        }

        private void StartRecording()
        {
            recordingIsRun = true;
            this.item.Text = "Stop Recording";
            this.recodingButton.Background = new ImageBrush(new BitmapImage(new Uri("pack://siteoforigin:,,,/image/stop.png")));
            int width = DesktopDuplicator.Instance.Width;
            int height = DesktopDuplicator.Instance.Height;
            videoStartTime = DateTime.Now;
            string timeStr = videoStartTime.ToString("yyyyMMddHHmmss");
            audioSource = new AudioSource(FPS);
            audioSource.OnGetPcmData += this.OnGetPcmData;
            videoWriter = new Mp4VideoWriter(timeStr + ".mp4", FPS, new System.Drawing.Size(width, height));
            recordingData = new RecordingData
            {
                RecordingName = timeStr,
            };

            //开启线程循环获取截图
            RunDesktopCapture();
            //开启定时获取鼠标位置
            RunMouseCapture();
            //this.Hide();
        }

        private void OnGetPcmData(byte[] data)
        {
            if (videoWriter != null)
            {
                videoWriter.WritePcmAudioFrame(data);
            }
        }

        private void StopRecording()
        {
            Console.WriteLine("StopRecording()");
            recordingIsRun = false;

            while ((recordingData != null && recordingData.EndTime == null))
            {
                Thread.Sleep(1);
            }
            MousePosition.Instance.Stop();
            this.item.Text = "Start Recording";
            this.recodingButton.Background = new ImageBrush(new BitmapImage(new Uri("pack://siteoforigin:,,,/image/record.png")));
        }

        private void show_click(object sender, EventArgs e)
        {
            this.Show();
        }

        /// <summary>
        /// 退出选项
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exit_Click(object sender, EventArgs e)
        {
            if (System.Windows.MessageBox.Show("Are you sure you want to quit?",
                                               "Exit",
                                                MessageBoxButton.YesNo,
                                                MessageBoxImage.Question,
                                                MessageBoxResult.No) == MessageBoxResult.Yes)
            {
                StopRecording();
                notifyIcon.Dispose();
                System.Windows.Application.Current.Shutdown();
            }
        }

        /// <summary>
        /// 鼠标单击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void notifyIcon_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                if (this.Visibility == Visibility.Visible)
                {
                    this.Visibility = Visibility.Hidden;
                }
                else
                {
                    this.Visibility = Visibility.Visible;
                    this.Activate();
                }
            }
        }

        /// <summary>
        /// 选择视频文件
        /// </summary>
        /// <returns></returns>
        private string OpenVideoFile()
        {
            string path = string.Empty;
            var openFileDialog = new Microsoft.Win32.OpenFileDialog()
            {
                Filter = "AVI Videos (*.mp4)|*.mp4"
            };
            var result = openFileDialog.ShowDialog();
            if (result == true)
            {
                path = openFileDialog.FileName;
            }
            return path;
        }
    }
}
